home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / SoftwareUpdate / CyberGraphiX Update / CV64VBlankHack.lha / CV64VBlankHack / CV64VBlankHack.c < prev    next >
C/C++ Source or Header  |  1996-08-28  |  7KB  |  275 lines

  1. /* Installs a new VBLANK handler that kicks in when a CyberGraphX screen
  2.    is being displayed.
  3.  
  4.    VBeamPos() is also patched to return the correct scan line.
  5.  
  6.    This is a HACK. It's Quick and it's Dirty. I don't care if it doesn't work
  7.    for you, it does for me.
  8.  
  9.    Done by Martin 'Leviticus' Blom in 1996 (lcs@lysator.liu.se).
  10.    Public Domain. Feel free to improve it, and perhaps write a more lowlevel version.
  11.    Just keep my name in it if you base anything on this.
  12. */
  13.  
  14. /*
  15. ** Graphic card settings
  16. */
  17.  
  18. #define MANUFACTURER  8512            // Phase 5
  19. #define PRODUCT       34              // CyberVision 64
  20. #define VGAOFFSET     0x02000000      // Where are the VGA registers located?
  21.  
  22. /*
  23. ** MARGIN is... well see the line where the period is set. It should be less than
  24. ** 1.0, but as close as possible without missing vblanks.
  25. ** If you set it to 5/10, for example, you'll loose 50% of your CPU power!
  26. ** 9/10 works fine on my A4000. If I didn't use timer.device, but used a
  27. ** level 6 timer directly instead, this number could probably be raised. But since
  28. ** I hate programs that uses CIA timers, I didn't.
  29. */
  30.  
  31. #define MARGIN        90/100
  32.  
  33.  
  34.  
  35.  
  36.  
  37. #include <exec/exec.h>
  38. #include <dos/dos.h>
  39. #include <devices/timer.h>
  40. #include <graphics/gfxbase.h>
  41. #include <hardware/intbits.h>
  42. #include <hardware/cia.h>
  43. #include <cybergraphics/cybergraphics.h>
  44. #include <libraries/configvars.h>
  45.  
  46. #include <proto/dos.h>
  47. #include <proto/exec.h>
  48. #include <proto/graphics.h>
  49. #include <proto/intuition.h>
  50. #include <proto/timer.h>
  51. #include <proto/cybergraphics.h>
  52. #include <proto/expansion.h>
  53.  
  54. extern struct ExecBase *SysBase;
  55. extern __far struct CIA ciaa;
  56.  
  57. extern void NewVBLANKHandler(void);
  58. extern void __asm CallVBLANKServers(register __a6 struct ExecBase *);
  59. extern LONG __asm WaitVBLANK( register __a0 UBYTE * );
  60. extern LONG __asm myReadEClock(void);
  61.  
  62. void start(void);
  63. void softcode (void);
  64. LONG __saveds newVBeamPos(void);
  65.  
  66. struct Library *TimerBase=NULL;
  67.  
  68. #define OFF     0    // Shut down
  69. #define ON      1    // Run
  70. #define STOPPED 2    // Has shut down
  71.  
  72. struct Data
  73. {
  74.   UWORD d_Flag;
  75.   struct MsgPort *d_Port;
  76. };
  77. struct Data *data;
  78.  
  79. struct NewVBLANKData
  80. {
  81.  ULONG    nd_OldEnable;     // Enables old VBLANK code
  82.  VOID     (*nd_Code)();     // Old iv_Code
  83. };
  84. struct NewVBLANKData *NewVBLANKdata;
  85.  
  86. struct MonitorInfo mi;
  87.  
  88. #define DEFPERIOD 1000 //00
  89. ULONG period=DEFPERIOD;
  90.  
  91. LONG     (*oldVBeamPos)();
  92.  
  93. UBYTE *vgaregs=NULL;
  94.  
  95. /*
  96. ** I dont know if it's just me, but isn't timer.device's ReadEClock() broken?
  97. ** Anyway, I use my own routine.
  98. */
  99.  
  100. LONG Eclock;               // E-clock value last VBLANK
  101. LONG Efreq;
  102. struct EClockVal eclockpad; // Unused
  103.  
  104. long main(void)
  105. {
  106.   struct ConfigDev *cd;
  107.  
  108.   cd=FindConfigDev( NULL, MANUFACTURER, PRODUCT );
  109.   if(!cd)
  110.     return 20;
  111.  
  112. // Graphics card found: 
  113.   vgaregs=(UBYTE *) cd->cd_BoardAddr+VGAOFFSET;
  114.  
  115.   if(NewVBLANKdata = AllocVec(sizeof(struct NewVBLANKData), MEMF_PUBLIC|MEMF_CLEAR))
  116.   {
  117.  
  118.     NewVBLANKdata->nd_OldEnable=TRUE;
  119. /*
  120. ** Change the vblank *HANDLER*.
  121. */
  122.  
  123. // Store old code segment and install our own (leave data segment untouched)
  124.     Disable();
  125.     NewVBLANKdata->nd_Code=SysBase->IntVects[INTB_VERTB].iv_Code;
  126.     SysBase->IntVects[INTB_VERTB].iv_Code=NewVBLANKHandler;
  127.     Enable();
  128.  
  129. //  Install new VBeamPos code
  130.     oldVBeamPos=SetFunction((struct Library *)GfxBase, -384, (ULONG (* )()) newVBeamPos);
  131.  
  132.     start();
  133.  
  134. //  Install old VBeamPos code
  135.     SetFunction((struct Library *)GfxBase, -384, (ULONG (* )()) oldVBeamPos);
  136.  
  137. // Restore old code segment
  138.     SysBase->IntVects[INTB_VERTB].iv_Code=NewVBLANKdata->nd_Code;
  139.  
  140.     FreeVec(NewVBLANKdata);
  141.   }
  142.   return NULL;
  143. }
  144.  
  145. void start(void)
  146. {
  147.   struct MsgPort *port;
  148.   struct Interrupt *softint;
  149.   struct timerequest *timereq;
  150.   ULONG  id;
  151.   BOOL   done=FALSE;
  152.   
  153.   if(data = AllocVec(sizeof(struct Data), MEMF_PUBLIC|MEMF_CLEAR))
  154.   {
  155.     if(port = AllocVec(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR))
  156.     {
  157.       NewList(&(port->mp_MsgList));
  158.       if(softint = AllocVec(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR))
  159.       {
  160.         softint->is_Code=softcode;
  161.         softint->is_Data=data;
  162.         softint->is_Node.ln_Pri=32;
  163.         
  164.         port->mp_Node.ln_Type = NT_MSGPORT;
  165.         port->mp_Flags= PA_SOFTINT;
  166.         port->mp_SigTask = (struct Task *) softint;
  167.         
  168.         if(timereq= (struct timerequest *) CreateIORequest(port, sizeof(struct timerequest)))
  169.         {
  170.           if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) timereq, 0))
  171.           {
  172.             TimerBase=(struct Library *) timereq->tr_node.io_Device;
  173.  
  174.             Efreq=ReadEClock(&eclockpad);   // Just get the E clock frequency
  175.             Printf("%ld\n",Efreq);
  176.  
  177.  
  178.             data->d_Flag=ON;
  179.             data->d_Port=port;
  180.             timereq->tr_node.io_Command=TR_ADDREQUEST;
  181.             timereq->tr_time.tv_micro=DEFPERIOD;
  182.             BeginIO((struct IORequest *) timereq);
  183.  
  184.             while(!done)
  185.             {
  186.  
  187. // Keep checking the frontmost intuition screen
  188.               id=GetVPModeID(&IntuitionBase->FirstScreen->ViewPort);
  189.               if(IsCyberModeID(id))
  190.               {
  191. // CyberGraphX screen
  192.                 if(GetDisplayInfoData(NULL,(UBYTE *) &mi, sizeof mi, DTAG_MNTR,id))
  193.                 {
  194.                   period=mi.TotalRows*mi.TotalColorClocks*280*MARGIN/1000;  // in µs
  195.                   NewVBLANKdata->nd_OldEnable=FALSE;
  196.                 }
  197.                 else
  198.                 {
  199.                   NewVBLANKdata->nd_OldEnable=TRUE;
  200.                   period=DEFPERIOD;
  201.                 }
  202.               }
  203.               else
  204.               {
  205. // Native screen
  206.                 NewVBLANKdata->nd_OldEnable=TRUE;
  207.                 period=DEFPERIOD;
  208.               }
  209.  
  210.               Delay(10);
  211.  
  212.               if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  213.               {
  214.                 done=TRUE;
  215.               }
  216.             }
  217.  
  218.             Printf("%ld\n",newVBeamPos());
  219.  
  220.             NewVBLANKdata->nd_OldEnable=TRUE;
  221.             period=DEFPERIOD;
  222.  
  223.             data->d_Flag=OFF;
  224.             while(data->d_Flag != STOPPED) Delay(10);
  225.  
  226.             CloseDevice((struct IORequest *) timereq);
  227.           }
  228.           DeleteIORequest((struct IORequest *) timereq);
  229.         }
  230.         FreeVec(softint);
  231.       }
  232.       FreeVec(port);
  233.     }
  234.     FreeVec(data);
  235.   }
  236. }
  237.  
  238. void __saveds __interrupt softcode(void)
  239. {
  240.   struct timerequest *timereq;
  241.   
  242.   timereq=(struct timerequest *) GetMsg(data->d_Port);
  243.   if( (timereq) && (data->d_Flag == ON) )
  244.   {
  245.     if(!(NewVBLANKdata->nd_OldEnable))
  246.     {
  247.       Eclock=WaitVBLANK(vgaregs);
  248.       CallVBLANKServers(SysBase);
  249.     }
  250.     timereq->tr_node.io_Command=TR_ADDREQUEST;
  251. // Period in µs. The main task keeps updating this value all the time.
  252.     timereq->tr_time.tv_micro=period;
  253.     BeginIO((struct IORequest *) timereq);
  254.   }
  255.   else
  256.     data->d_Flag=STOPPED;
  257. }
  258.  
  259. LONG __saveds newVBeamPos(void)
  260. {
  261.   LONG ediff;
  262.  
  263.   if(NewVBLANKdata->nd_OldEnable)
  264.     return (*oldVBeamPos)();
  265.  
  266.   ediff=Eclock-myReadEClock();
  267.   if(ediff<0)
  268.     ediff+=65536;
  269.  
  270. // Return (approx) current raster line. mi.TotalRows disappears...
  271. // HOWEVER: The range is NOT limited to 511 anymore. I don't know if this is a problem?
  272.  
  273.   return ediff*(1000000000/280/mi.TotalColorClocks)/Efreq;
  274.  
  275. }